package ferp.center.server.servlet;

import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import ferp.center.network.request.RequestPollSubmit;
import ferp.center.server.Action;
import ferp.center.server.entity.PollResult;
import ferp.center.server.poll.Polls;

import javax.persistence.EntityManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * User: olegs
 * Date: 10/05/2014 16:53
 */
public class PollSubmit extends HttpServlet
{
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
  {
    Action.execute(request, response, RequestPollSubmit.class, new Action.Read<RequestPollSubmit, Boolean>()
    {
      @SuppressWarnings("unchecked")
      @Override
      public Boolean run(EntityManager em, RequestPollSubmit input) throws IOException
      {
        if (input.poll != Polls.ID)
        {
          log("invalid poll ID " + input.poll);
          return false;
        }

        if (!Polls.enabled)
        {
          log("poll is disabled");
          return false;
        }

        MemcacheService mcs = MemcacheServiceFactory.getMemcacheService();
        String key = POLL_ANSWER_COUNT + input.answers;
        long starting = 0L;

        // in case the value is not cached check if it presents in the datastore to prevent counter reset because
        // of memcache failure
        if (mcs.get(key) == null)
        {
          log("cached value for answer [" + input.answers + "] does not exist, trying to get it from DS");

          PollResult r = em.find(PollResult.class, input.answers);

          if (r != null)
          {
            starting = r.getCount();

            log("successfully loaded from DS, value=" + starting);
          }
          else
            log("not found!");
        }

        // increment the appropriate cached value
        long incremented = mcs.increment(key, 1, starting);

        log("incrementing counter for answer " + input.answers + ", count=" + incremented);

        // flush the cached values
        flush(em, mcs);

        return true;
      }
    });
  }

  // invoked by cron
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
  {
    Action.execute(request, new Action.Task()
    {
      @Override
      protected void run(EntityManager em, HttpServletRequest request) throws IOException
      {
        MemcacheService mcs = MemcacheServiceFactory.getMemcacheService();

        log("flushing cached poll results...");

        // flush the cached values
        flush(em, mcs);
      }
    });
  }

  private static final long FLUSH_INTERVAL = 1000 * 60;

  private static final String POLL_ANSWER_COUNT           = "poll_answer_count_";
  private static final String POLL_ANSWER_LAST_FLUSH_DATE = "poll_answer_last_flush_date_";

  private void flush(EntityManager em, MemcacheService mcs)
  {
    long now = System.currentTimeMillis(), refused = 0, interested = 0;

    for (String key : Polls.answers())
    {
      String mkf = POLL_ANSWER_LAST_FLUSH_DATE + key;
      String mkc = POLL_ANSWER_COUNT + key;
      Long flushed = (Long)mcs.get(mkf);
      Long count = (Long)mcs.get(mkc);

      if (count != null)
      {
        if (key.equals("x") || key.equals("3"))
          refused += count;
        else
          interested += count;

        if (flushed == null || now - flushed > FLUSH_INTERVAL)
        {
          PollResult r = em.find(PollResult.class, key);

//          log("time to write counter for answer [" + key + "]...");

          if (r == null)
          {
            r = new PollResult(key);
            em.persist(r);

            log("created new DS entry");
          }

          // write only if changed
          if (r.getCount() != count)
          {
            log("writing value of " + count);

            // write to DS
            r.setCount(count);
            // update last flush date
            mcs.put(mkf, now);
          }
//          else
//            log("counter not changed (" + count + ")");
        }
      }
    }

    long ri = refused + interested;

    log("total answers: " + ri + ", interested: " + interested + " (" + (ri > 0 ? (interested * 100 / ri) : 0) + "%)");
  }
}
